"""
实名认证相关接口
"""

# 导入标准库和第三方库
from fastapi import APIRouter, HTTPException, Depends, status  # FastAPI相关模块
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials  # HTTP安全认证
from sqlalchemy.orm import Session  # SQLAlchemy会话
from pydantic import BaseModel  # Pydantic数据模型
from typing import Optional  # 类型提示
import json  # JSON处理

# 导入项目内部模块
from starlette.responses import JSONResponse  # Starlette响应类
from database import get_db  # 数据库会话依赖
from models.auth import UserAuth  # 用户认证模型
from models.user import User  # 用户模型
from tools.auth import verify_token  # JWT token验证
from tools.ocr import ocr_id_card  # OCR识别工具

# 创建API路由实例
router = APIRouter()

# 创建HTTP Bearer认证实例
security = HTTPBearer()


class OcrRequest(BaseModel):
    """OCR请求体（image_url 与 image_base64 二选一）"""
    image_url: Optional[str] = None
    image_base64: Optional[str] = None
    card_side: str  # 正反面标识：front 或 back
    user_id: int  # 用户ID


class OcrResponse(BaseModel):
    """OCR响应"""
    success: bool
    message: str
    data: Optional[dict] = None


class RealNameAuthResponse(BaseModel):
    """实名认证响应"""
    success: bool
    message: str
    auth_info: Optional[dict] = None


# 导入七牛云SDK
from qiniu import Auth


@router.get("/qiniu/")
async def get_upload_token():
    """
    获取七牛云上传token
    
    返回:
        七牛云上传token
    """
    try:
        # 需要填写你的 Access Key 和 Secret Key
        access_key = 'vsZgyM6Asrl0k2vxBttBA45RD7txWFz8RbYma68H'
        secret_key = 'N8sof55UESDrBDyy-_9AIR1ZfUwsB1_89Mt4efo_'
        
        # 构建鉴权对象
        q = Auth(access_key, secret_key)
        
        # 要上传的空间
        bucket_name = 'wlgy'

        # 3600为token过期时间，秒为单位。3600等于一小时
        # 添加policy参数，允许指定key
        policy = {
            'scope': bucket_name,
            'deadline': 3600
        }
        
        # 生成上传token
        token = q.upload_token(bucket_name, None, 3600, policy)

        # 打印调试信息
        print(f"生成的七牛云token: {token[:50]}...")
        
        # 返回成功响应
        return JSONResponse({"code": 10000, 'data': token})
    except Exception as e:
        # 捕获异常并返回错误响应
        print(f"生成七牛云token失败: {e}")
        return JSONResponse({"code": 500, 'message': f'生成token失败: {str(e)}'})


@router.post("/ocr/idcard", response_model=OcrResponse)
async def ocr_id_card_endpoint(
    request: OcrRequest,  # OCR请求数据
    credentials: HTTPAuthorizationCredentials = Depends(security),  # 认证凭据
    db: Session = Depends(get_db)  # 数据库会话
):
    """
    身份证OCR识别接口
    调用百度OCR工具识别身份证信息并写入数据库
    """
    try:
        # 1. 验证token
        token = credentials.credentials
        payload = verify_token(token)
        
        # 检查token是否有效
        if not payload:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="无效的token"
            )
        
        # 2. 验证用户ID是否匹配token中的用户ID
        token_user_id = int(payload.get("sub"))
        if token_user_id != request.user_id:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="用户ID不匹配"
            )
        
        # 3. 验证card_side参数
        if request.card_side not in ["front", "back"]:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="card_side必须是'front'或'back'"
            )

        # 4. 校验图片入参（二选一）
        if not request.image_url and not request.image_base64:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="必须提供 image_url 或 image_base64 其中之一"
            )
        
        # 5. 把任务添加到Redis队列，而不是立即处理
        # 这样做的好处：用户不需要等待OCR识别完成，立即返回响应
        # 实际的处理会在后台的定时任务中进行
        from tools.redis_queue import push_task_to_queue, get_queue_length
        
        # 准备任务数据，把所有需要的信息打包成字典
        task_data = {
            "user_id": request.user_id,              # 用户ID
            "card_side": request.card_side,          # 身份证正反面
            "image_base64": request.image_base64,    # 图片base64编码
            "image_url": request.image_url           # 图片URL（如果有的话）
        }
        
        # 把任务添加到队列中
        # push_task_to_queue会把任务存到Redis队列里
        success = push_task_to_queue(task_data)
        
        # 打印详细的队列信息，方便调试
        if success:
            queue_length = get_queue_length()
            print(f"[队列信息] 任务已成功添加到队列，当前队列长度: {queue_length}")
        else:
            print(f"[队列信息] 任务添加失败，请检查Redis是否正常运行")
        
        # 检查是否成功添加到队列
        if not success:
            # 如果添加失败，返回错误
            return OcrResponse(
                success=False,
                message="任务添加失败，请稍后重试"
            )
        
        # 如果成功添加到队列，立即返回成功响应
        # 告诉用户任务已经提交，正在处理中
        queue_length = get_queue_length()
        
        return OcrResponse(
            success=True,
            message="任务已提交，正在处理中，请稍后查看结果",
            data={
                "status": "queued",           # queued表示已经加入队列
                "queue_length": queue_length,  # 队列中还有多少个任务（包括你刚添加的这个）
                "queue_position": queue_length  # 你在队列中的位置
            }
        )
                
    except HTTPException:
        # 重新抛出HTTP异常
        raise
    except Exception as e:
        # 捕获其他异常
        print(f"[错误] OCR识别接口异常: {e}")
        import traceback
        traceback.print_exc()
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"服务器错误: {str(e)}"
        )


@router.get("/queue/status")
async def get_queue_status():
    """
    查看队列状态的接口
    不需要登录就能查看，方便调试和监控
    """
    try:
        from tools.redis_queue import get_queue_length
        
        # 获取队列中的任务数量
        queue_length = get_queue_length()
        
        # 返回队列状态信息
        return {
            "success": True,
            "queue_length": queue_length,
            "message": f"队列中还有 {queue_length} 个任务等待处理"
        }
    except Exception as e:
        # 捕获异常并返回错误响应
        return {
            "success": False,
            "queue_length": 0,
            "message": f"获取队列状态失败: {str(e)}"
        }


@router.get("/info", response_model=RealNameAuthResponse)
async def get_real_name_auth_info(
    credentials: HTTPAuthorizationCredentials = Depends(security),  # 认证凭据
    db: Session = Depends(get_db)  # 数据库会话
):
    """
    获取当前用户的实名认证信息
    """
    try:
        # 验证token
        token = credentials.credentials
        payload = verify_token(token)
        
        # 检查token是否有效
        if not payload:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="无效的token"
            )
        
        # 从token中提取用户ID
        user_id = int(payload.get("sub"))
        
        # 查询认证信息
        user_auth = db.query(UserAuth).filter(UserAuth.user_id == user_id).first()
        
        # 检查用户是否已认证
        if not user_auth:
            return RealNameAuthResponse(
                success=False,
                message="尚未进行实名认证"
            )
        
        # 返回认证信息（隐藏部分身份证号）
        id_card_masked = user_auth.id_card_num[:6] + "********" + user_auth.id_card_num[-4:] if len(user_auth.id_card_num) >= 10 else user_auth.id_card_num
        
        # 构造响应数据
        response_data = {
            "id": user_auth.id,
            "real_name": user_auth.real_name,
            "id_card_num": id_card_masked,
            "gender": user_auth.gender,
            "nation": user_auth.nation,
            "birth": user_auth.birth,
            "address": user_auth.address,
            "issuing_authority": user_auth.issuing_authority,
            "valid_date": user_auth.valid_date,
            "is_verified": user_auth.is_verified,
            "created_at": user_auth.created_at.isoformat() if user_auth.created_at else None,
            "updated_at": user_auth.updated_at.isoformat() if user_auth.updated_at else None
        }
        
        # 返回成功响应
        return RealNameAuthResponse(
            success=True,
            message="获取成功",
            auth_info=response_data
        )
        
    except HTTPException:
        # 重新抛出HTTP异常
        raise
    except Exception as e:
        # 捕获其他异常
        print(f"[错误] 获取实名认证信息异常: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"服务器错误: {str(e)}"
        )